﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Text;

namespace RAD.LightOne
{
    #region Documentation
    /// <summary>
    /// MyObject tipado através de genérics, deve ser sempre a base para construção de novos objetos do LightOne.
    /// </summary>
    #endregion
    [Serializable]
    public abstract class MyObject<T> : MyObject where T : MyObject
    {
        #region Constructors

        protected MyObject(Guid id) : base(id) { }

        public MyObject() : base() { }

        #endregion

        #region Methods

        public static T FindById(IDbTransaction trx, Guid id)
        {
            if (trx == null) throw new ArgumentNullException("trx");

            Finder finder = new Finder();
            return finder.FindById(typeof(T), id, trx) as T;
        }

        #region Documentation
        /// <summary>
        /// Retorna uma instância de um objeto buscando por seu id.
        /// </summary>
        /// <param name="id">Identificador único da instância a ser recuperada.</param>
        #endregion
        public static T FindById(Guid id)
        {
            return MyObject.FindById(typeof(T), id) as T;
        }

        #region Documentation
        /// <summary>
        /// Retorna uma coleção de objetos de acordo com o array de id's passado.
        /// </summary>
        /// <param name="ids">array de id's a serem buscados</param>
        /// <returns>coleção de T</returns>
        #endregion Documentation
        public static T[] FindById(Guid[] ids)
        {
            return MyObject.FindById(typeof(T), ids) as T[];
        }

        #region Documentation
        /// <summary>
        /// Método que recebe um instrução sql a avalia e retorna uma coleção de MyObject como resultado
        /// da expressão. Deve OBRIGATÓRIAMENTE possir os campos "id" e "class_name" na instrução "select" passada.
        /// </summary>
        /// <param name="sql">instrução select para busca dos dados.</param>
        /// <param name="args">argumentos que serão analizados e concatenados juntamente com a sql.</param>
        #endregion Documentation
        public static T[] FindBySql(string sql, params object[] args)
        {
            List<T> objects = new List<T>();
            
            foreach(MyObject instance in MyObject.FindBySql(sql,args))
            {
                if(instance.ImplicitlyIs(typeof(T))) objects.Add(instance as T);
            }

            return objects.ToArray();
        }

        #region Documentation
        /// <summary>
        /// Método que recebe um instrução sql a avalia e retorna uma coleção de MyObject como resultado
        /// da expressão. Deve OBRIGATÓRIAMENTE possir os campos "id" e "class_name" na instrução "select" passada.
        /// </summary>
        /// <param name="trx">Transação utilizada na consulta.</param>
        /// <param name="sql">instrução select para busca dos dados.</param>
        /// <param name="args">argumentos que serão analizados e substituirão os parâmetros numerados na sql.</param>
        #endregion Documentation
        public static T[] FindBySql(IDbTransaction trx, string sql, params object[] args)
        {
            List<T> objects = new List<T>();

            foreach (MyObject instance in MyObject.FindBySql(trx, sql, args))
            {
                if (instance.ImplicitlyIs(typeof(T))) objects.Add(instance as T);
            }

            return objects.ToArray();
        }

        #region Documentation
        /// <summary>
        /// Retorna todas as instâncias de um tipo.
        /// </summary>
        #endregion
        public static T[] FindAll()
        {
            List<T> objects = new List<T>();

            foreach (MyObject instance in MyObject.FindAll(typeof(T)))
            {
                if (instance.ImplicitlyIs(typeof(T))) objects.Add(instance as T);
            }

            return objects.ToArray();
        }

        public static IEnumerable<T> EnumerableFindById(Guid[] ids)
        {
            foreach (MyObject instance in MyObject.EnumerableFindById(typeof(T),ids))
            {
                if (instance.ImplicitlyIs(typeof(T)))
                {
                    yield return instance as T;
                }
            }
        }

        public static IEnumerable<T> EnumerableFindAll()
        {
            foreach (MyObject instance in MyObject.EnumerableFindAll(typeof(T)))
            {
                if (instance.ImplicitlyIs(typeof(T)))
                {
                    yield return instance as T;
                }
            }
        }

        public static IEnumerable<T> EnumerableFindBySql(string sql, params object[] args)
        {
            foreach (MyObject instance in MyObject.EnumerableFindBySql(sql, args))
            {
                if (instance.ImplicitlyIs(typeof(T)))
                {
                    yield return instance as T;
                }
            }
        }

        #endregion
    }
}
